<template>
  <div class='merge_topo_warp'>
    <div class='merge_left_action'>
      <h4 class='mb12'>归并</h4>
      <ga-form :label-col-props="{ span: 6 }" :wrapper-col-props="{ span: 16 }" class='custom_horizontal_form'
        ref='formRef' :model="formData" >
        <ga-form-item label='名称' name='mergeLabel' initialValue='' :rules="[
          { required: true, message: '请输入归并名称' },
          { validator: checkMergeLabel },
        ]">
          <ga-input />
        </ga-form-item>
        <ga-form-item label='关联端点'>
          <div class='ipport_list_item' :key="node.id" v-for="node in nowMergeList">{{ node.workloadName }}</div>
        </ga-form-item>
        <ga-form-item :wrapper-col-props="{ offset: 6, span: 16 }">
          <div class='flex-end'>
            <ga-button type="secondary"  class='mr8' @click="onCancelMerge">重置</ga-button>
            <ga-button type='primary' @click="onSaveMerge">确认</ga-button>
          </div>
        </ga-form-item>
      </ga-form>
    </div>
    <div ref="topoRef" id='mergeTopo' style="flex:1;overflow: hidden;"></div>
    <div class='edit_topo_footer' :style="isFullScreen ? footerFullscreenStyle : {}">
      <ga-button type="secondary" class='mr8' @click="() => emits('on-cancel')">取消</ga-button>
      <ga-button type='primary' class='mr8' @click="() => onConfirm(mergeTopoData.nodes)">确定</ga-button>
    </div>
  </div>
</template>

<script setup>
import G6 from '@antv/g6';
import { onMounted, onUnmounted, watch, ref, reactive } from 'vue';
import { Message } from '@garco-design/web-vue';
import { clearAllStats, getIpPortMergeData } from './topoService'
import { nameTooltip } from './graphPlugins'
import { mergeTopoInteraction } from './topoInteraction';
import {cloneDeep} from 'lodash'
const footerFullscreenStyle = {
  left: 0,
  bottom: 0,
  width: '100%',
}
const props = defineProps({
  topoData: Object,
  systemId: String,
  isFullScreen: Boolean,

})
const emits = defineEmits(['on-cancel', 'on-confirm'])

const mergeTopoData = ref({ nodes: [], edges: [], combos: [] })
const nowMergeList = ref([])
const formData = reactive({mergeLabel: ''})
const formRef = ref()
const topoRef = ref()
const graph = ref()
// 当监听到window对象或者container的大小发生变化是，改变画布大小
const changeGraphSize = () => {
  if (graph.value && topoRef.value) {
    const { clientWidth, clientHeight } = topoRef.value;
    graph.value.changeSize(clientWidth, clientHeight);
    // graph.value.fitCenter()
  }
}
const draw = () => {
  if (!mergeTopoData.value.nodes.length) {
    topoRef.value.innerHTML = '';
    return;
  }
  const { nodes, edges, combos } = mergeTopoData.value;
  const data = { nodes, edges, combos };
  G6.Util.processParallelEdges(data.edges, 15, 'quadratic', undefined, 'loop');

  const width = topoRef.value.clientWidth;
  const height = topoRef.value.clientHeight;
  topoRef.value.innerHTML = '';

  const graphInst = new G6.Graph({
    container: 'mergeTopo',
    width,
    height,
    fitCenter: true,
    autoPaint: false,
    plugins: [nameTooltip],
    modes: {
      default: [
        {
          type: 'zoom-canvas',
          minZoom: 0.5,
          maxZoom: 2
        },
        {
          type: 'drag-node',
          onlyChangeComboSize: true
        },
        'drag-combo',
        'drag-canvas'
      ],
      showComponent: []
    },
    defaultNode: {
      type: 'custom-merge-node'
    },
    defaultEdge: {
      style: {
        endArrow: {
          path: G6.Arrow.triangle(5, 5, 0),
          fill: '#AAAAAA',
        },
        lineWidth: 1,
        stroke: '#AAAAAA',
      },
    },
    layout: {
      type: 'custom-merge-layout',
      nodeWidth: 130,
      nodeHeight: 68,
      wSpace: 46,
      hSpace: 48,
      comboOffsetX: 20,
      comboOffsetY: 20,
    },
    defaultCombo: {
      type: 'custom-merge-combo',
      size: [132, 0],
      padding: [54, 16, 16, 16],
    },
  });
  graphInst.data(data);
  graphInst.render();

  graph.value = graphInst;

  for (let key in mergeTopoInteraction) {
    graphInst.on(key, (evt) => {
      const handler = mergeTopoInteraction[key]
      handler(evt, graph.value)
    })
  }
  graphInst.on('node:click', onNodeClick);

  graphInst.on('combo:click', onComboClick);

}
const onNodeClick = (evt) => {
  const { item } = evt;
  const mergeList = cloneDeep(nowMergeList.value);
  const model = item.getModel();
  if (model.workloadKind !== 'vm') {
    Message.warning('虚机应用以及外部应用才能进行归并');
    return;
  }
  if (model.mergeLabel) {
    Message.warning('该节点已被归并');
    return;
  }
  const index = findIndex(mergeList, { id: model.id });
  if (index > -1) {
    mergeList.splice(index, 1);
    graph.value.setItemState(item, 'active', false);
  } else {
    mergeList.push(model);
    graph.value.setItemState(item, 'active', true);
  }
  nowMergeList.value = mergeList
  // this.setState({ nowMergeList });
}
const onComboClick = (evt) => {
  const { item } = evt;
  const targetName = evt.target.get('name');
  const model = item.getModel();
  if (targetName === 'cancel-merge') {
    const { mergeTopoData } = this.state;
    const { nodes, edges, combos = [] } = cloneDeep(mergeTopoData.value);
    const comboNodes = item.getNodes().map(node => node.getModel());
    forEach(nodes, node => {
      if (findIndex(comboNodes, { id: node.id }) > -1) {
        delete node.comboId;
        delete node.mergeLabel;
      }
    })
    remove(combos, { id: model.id });
    mergeTopoData.value = { nodes, edges, combos }
    // this.setState({
    //   mergeTopoData: { nodes, edges, combos },
    // }, this.draw)
  } else {
    evt.item._xxx = true;
    graph.value.collapseExpandCombo(item);
  }
}
const onSaveMerge = () => {
  formRef.value.validateFields().then(values => {

    if (!nowMergeList.value.length) {
      Message.warning('未选择需要归并的节点');
      return;
    }
    const { nodes, edges, combos } = cloneDeep(mergeTopoData.value);
    forEach(nodes, node => {
      if (findIndex(nowMergeList, { id: node.id }) > -1) {
        node.comboId = values.mergeLabel;
        node.mergeLabel = values.mergeLabel;
      }
    })
    combos.push({
      id: values.mergeLabel,
      label: values.mergeLabel,
      labelText: values.mergeLabel,
      collapsed: true,
    })
    mergeTopoData.value = { nodes, edges, combos }
    this.setState({
      mergeTopoData: { nodes, edges, combos },
    }, () => {
      this.onCancelMerge();
      this.draw();
    })
  })
}

const onCancelMerge = () => {
  formRef.value?.resetFields();
  nowMergeList.value = []
  clearAllStats(graph.value);
}
const checkMergeLabel = async (value, cb) => {
  const { nodes } = mergeTopoData.value
  if (value) {
    if (findIndex(nodes, { mergeLabel: value }) > -1) {
      throw new Error('已存在相同归并名称');
    }
  }
  cb()
}
onMounted(() => {
  mergeTopoData.value = getIpPortMergeData(props.topoData)
  console.log(mergeTopoData.value, 'merge data');
  draw()
  window.addEventListener('resize', changeGraphSize);
})
watch(() => props.topoData, (newV) => {
  mergeTopoData.value = getIpPortMergeData(newV)
})
watch(mergeTopoData, () => {


  draw()
})
watch(() => props.isFullScreen, () => {
  changeGraphSize()
})
onUnmounted(() => {
  window.removeEventListener('resize', changeGraphSize)
})
</script>

<style scoped lang="scss">
.merge_topo_warp {
  flex: 1;
  overflow: hidden;
  display: flex;

  .merge_left_action {
    width: 300px;
    // height: calc(100% - 38px);
    padding-top: 20px;
    background-color: #FFFFFF;
    border-right: 1px solid #DCDCDC;
    overflow-y: auto;

    .ipport_list_item {
      word-break: break-all;
      margin-top: 5px;
    }
  }
  .edit_topo_footer {
        position: absolute;
        left: -12px;
        bottom: -12px;
        height: 50px;
        width: calc(100% + 12px);
        display: flex;
        justify-content: flex-end;
        align-items: center;
        box-shadow: 0 -2px 3px -1px #00000026;
        background: #FFFFFF;
    }
}
</style>
